//=======================================================================//
//= Global variable define.											    =//
//=======================================================================//
#include <wx/string.h>
#include <wx/sizer.h>
#include <wx/fontenum.h>
#include <wx/msgdlg.h>
#include <wx/filedlg.h>
#include "Debug.h"
#include "ControlID.h"
#include "TextToolWindow.h"
#include "GeneralToolBar.h"
#include "FontToolBar.h"
#include "Settings.h"
#include "GlobalEvents.h"
#include "Utility.h"
#include "WorkThread.h"

//=======================================================================//
//= Global variable define.											    =//
//=======================================================================//

//=======================================================================//
//= Event table.													    =//
//=======================================================================//
BEGIN_EVENT_TABLE(TextToolWindow, sptChildWindowBase)
	EVT_ACTIVATE(								TextToolWindow::OnWindowActived)
	EVT_PAINT_FONT(EVT_PAINT_FONT_CHANGED,		TextToolWindow::OnFontChanged)
	EVT_GLOBAL_SETTINGS(EVT_SETTING_CHANGED,	TextToolWindow::OnSettingChanged)
	EVT_TEXT(ID_CTRL_TEXT_INPUT,				TextToolWindow::OnTextChanged)
	EVT_SIZE(									TextToolWindow::OnSizeChanged)
	EVT_TEXT_SEL(ID_CTRL_TEXT_INPUT, 			TextToolWindow::OnTextSelectionChange)
END_EVENT_TABLE()

//=======================================================================//
//= Function define.										            =//
//=======================================================================//
TextToolWindow::TextToolWindow(wxWindow* pclsParent)
: sptChildWindowBase(pclsParent, wxID_ANY)
{
	/*----------------------------------*/
	/* Process							*/
	/*----------------------------------*/
	(void)_create(pclsParent);
	m_bIsChanged = false;
}

TextToolWindow::TextToolWindow(wxWindow* pclsParent, const wxString& cstrFilePath)
: sptChildWindowBase(pclsParent, wxID_ANY, cstrFilePath)
{
	/*----------------------------------*/
	/* Process							*/
	/*----------------------------------*/
	(void)_create(pclsParent);
	if((nullptr != m_pclsInputTextCtrl) && (wxFileName::Exists(cstrFilePath)))
	{
		m_pclsInputTextCtrl->OpenFile(cstrFilePath);
	}
}

TextToolWindow::~TextToolWindow(void)
{
	/*----------------------------------*/
	/* Process							*/
	/*----------------------------------*/
	/* Do nothing. */
	WorkThreadMgr::Instance().StopThread();
}

void TextToolWindow::_create(wxWindow* pclsParent)
{
	/*----------------------------------*/
	/* Variable Declaration				*/
	/*----------------------------------*/
	wxBoxSizer*			pclsRootSizer = new wxBoxSizer(wxVERTICAL);
	wxBoxSizer*			pclsInputSizer = new wxBoxSizer(wxHORIZONTAL);
	wxBoxSizer*			pclsPerviewSizer = new wxBoxSizer(wxVERTICAL);

	/*----------------------------------*/
	/* Initialize						*/
	/*----------------------------------*/
	// Initialize members.
	m_pclsPerviewPanel =	nullptr;
	m_pclsInputTextCtrl =	nullptr;
	m_pclsParentFrame =		pclsParent;
	// Fit parent size.
	Layout();
	/*----------------------------------*/
	/* Process							*/
	/*----------------------------------*/
	// Set sizer.
	pclsRootSizer->Add( pclsPerviewSizer, 0, wxEXPAND, 5);
	pclsRootSizer->Add( pclsInputSizer, 1, wxEXPAND, 5);
	// Create input sizer.
	m_pclsInputTextCtrl = new InputTextCtrl(this, ID_CTRL_TEXT_INPUT);
	pclsInputSizer->Add( m_pclsInputTextCtrl, 1, wxEXPAND, 5);
	// Create preview sizer.
	wxSize clsSizeInPixelUnit((GetClientSize().GetWidth()-1)/GlobalPreviewSettings().PixelUnitSize().GetWidth()+1, GlobalPaintFont().GetSize());
	DBG_LOG("Initializing preview panel size in pixel is w:%d, h:%d.", clsSizeInPixelUnit.GetWidth(), clsSizeInPixelUnit.GetHeight());
	m_pclsPerviewPanel = new TextPaintCtrl(this, wxID_ANY, clsSizeInPixelUnit, GlobalPreviewSettings().GetBackgroundColour());
	/* Update paint font. */
	m_pclsPerviewPanel->SetFont(GlobalPaintFont());
	pclsPerviewSizer->Add( m_pclsPerviewPanel, 1, wxEXPAND, 5 );
	// Update paint configuration.
	_updatePaintConfig();
	// Layout.
	SetSizer(pclsRootSizer);
	Layout();
}

void TextToolWindow::_resizePerviewPanel(int iFontSize)
{
	/*----------------------------------*/
	/* Process							*/
	/*----------------------------------*/
	if(nullptr != m_pclsPerviewPanel)
	{
		m_pclsPerviewPanel->AutoHorizontalPixelNumber();
		m_pclsPerviewPanel->SetVerticalPixelNumber(iFontSize);
		Layout();
	}
}

void TextToolWindow::_updatePaintConfig(void)
{
	/*----------------------------------*/
	/* Process							*/
	/*----------------------------------*/
	m_pclsPerviewPanel->SetPanelColour(GlobalPreviewSettings().GetBackgroundColour(), false);
	m_pclsPerviewPanel->SetPixelColour(GlobalPreviewSettings().GetForegroundColour(), false);
	m_pclsPerviewPanel->SetGridColor(GlobalPreviewSettings().GetGridColour());
	DBG_LOG("Panel colour is #%06X.", CSS_LIKE_COLOR(GlobalPreviewSettings().GetBackgroundColour()));
    DBG_LOG("Pixel colour is #%06X.", CSS_LIKE_COLOR(GlobalPreviewSettings().GetForegroundColour()));
    DBG_LOG("Grid colour is #%06X.",  CSS_LIKE_COLOR(GlobalPreviewSettings().GetGridColour()));
}

void TextToolWindow::_paintText(const wxString& cstrText)
{
	/*----------------------------------*/
	/* Process							*/
	/*----------------------------------*/
	if(nullptr != m_pclsPerviewPanel)
	{
		m_pclsPerviewPanel->PaintText(cstrText);
		m_pclsPerviewPanel->RefreshDisplay();
	}
}

wxString TextToolWindow::GetInput(void) const
{
	return m_pclsInputTextCtrl->GetValue();
}

void TextToolWindow::OnSizeChanged(wxSizeEvent& clsEvent)
{
	/*----------------------------------*/
	/* Process							*/
	/*----------------------------------*/
	DBG_LOG("Resize text tool window.");
	_resizePerviewPanel(GlobalPaintFont().GetHeight());
	_paintText(m_pclsInputTextCtrl->GetValue());
}

void TextToolWindow::OnTextChanged(wxCommandEvent& clsEvent)
{
	/*----------------------------------*/
	/* Process							*/
	/*----------------------------------*/
	_paintText(m_pclsInputTextCtrl->GetValue());
	m_bIsChanged = true;
}

void TextToolWindow::OnTextSelectionChange(TextSelectEvent& clsEvent)
{
	/*----------------------------------*/
	/* Process							*/
	/*----------------------------------*/
	if(clsEvent.GetText().Length() > 0)
	{
		/* Paint text with selection. */
		_paintText(clsEvent.GetText());
	}
	else
	{
		/* Paint text input content. */
		_paintText(m_pclsInputTextCtrl->GetValue());
	}
}

void TextToolWindow::OnFontChanged(wxCommandEvent& clsEvent)
{
	/*----------------------------------*/
	/* Process							*/
	/*----------------------------------*/
	DBG_LOG("Text font changed.");
	/* Set new paint font. */
	m_pclsPerviewPanel->SetFont(GlobalPaintFont());
	/* Resize preview panel. */
	_resizePerviewPanel(GlobalPaintFont().GetHeight());
	/* Repaint all text. */
	_paintText(m_pclsInputTextCtrl->GetValue());
	clsEvent.StopPropagation();
}

void TextToolWindow::OnSettingChanged(wxCommandEvent& clsEvent)
{
	/*----------------------------------*/
	/* Variable Declaration				*/
	/*----------------------------------*/
	wxEvtHandler* pclsParentEvtHandler = wxWindow::GetParent();

	/*----------------------------------*/
	/* Process							*/
	/*----------------------------------*/
	if(EVT_SETTING_CHANGED == clsEvent.GetId())
	{
		/* Process event in main frame. */
		pclsParentEvtHandler->ProcessEvent(clsEvent);
		/* Apply new settings. */
		m_pclsPerviewPanel->SetGridColor(ConfigurationInstance().PanelConfiguration().GetGridColour());
		m_pclsPerviewPanel->SetPanelColour(ConfigurationInstance().PanelConfiguration().GetBackgroundColour(), false);
		m_pclsPerviewPanel->SetPixelColour(ConfigurationInstance().PanelConfiguration().GetForegroundColour(), true);
		DBG_LOG("Preview panel configuration updated.");
		DBG_LOG("Panel colour is 0x%08X.", GlobalPreviewSettings().GetBackgroundColour().GetRGB());
		DBG_LOG("Pixel colour is 0x%08X.", GlobalPreviewSettings().GetForegroundColour().GetRGB());
		DBG_LOG("Grid colour is 0x%08X.", GlobalPreviewSettings().GetGridColour().GetRGB());
	}
	clsEvent.Skip();
}

void TextToolWindow::OnWindowActived(wxActivateEvent& clsEvent)
{
	/*----------------------------------*/
	/* Process							*/
	/*----------------------------------*/
	if(clsEvent.GetActive())
	{
		DBG_LOG("Text window is actived.");
		_resizePerviewPanel(GlobalPaintFont().GetHeight());
		_paintText(m_pclsInputTextCtrl->GetValue());
		clsEvent.StopPropagation();
	}
	else
	{
		clsEvent.Skip();
	}
}

bool TextToolWindow::StartProcess(wxEvtHandler* pclsEventHandler)
{
	/*----------------------------------*/
	/* Process							*/
	/*----------------------------------*/
	return WorkThreadMgr::Instance(ID_WORK_THREAD).StartThread(pclsEventHandler, TextWorkThread::New(m_pclsInputTextCtrl->GetValue()));
}

bool TextToolWindow::OpenFile(void)
{
	/*----------------------------------*/
	/* Variable Declaration				*/
	/*----------------------------------*/
	wxFileDialog			clsOpenFileDialog(this, wxT("Save text file."), wxEmptyString, wxEmptyString,
										//wxT("Text file (*.txt)|*.txt|All files (*.*)|*.*"), wxFD_OPEN);
										wxT("Text file (*.txt)|*.txt"), wxFD_OPEN|wxFD_FILE_MUST_EXIST);
	bool					bReturn = false;

	/*----------------------------------*/
	/* Process							*/
	/*----------------------------------*/
	if(wxID_OK == clsOpenFileDialog.ShowModal())
    {
    	bReturn = OpenFile(clsOpenFileDialog.GetPath());
    }

    return bReturn;
}

bool TextToolWindow::OpenFile(const wxString& cstrPath)
{
	/*----------------------------------*/
	/* Variable Declaration				*/
	/*----------------------------------*/
	bool					bReturn = true;

	/*----------------------------------*/
	/* Process							*/
	/*----------------------------------*/
	// Open the file.
	bReturn = m_pclsInputTextCtrl->OpenFile(cstrPath);
	if(bReturn)
	{
		SetFilePath(cstrPath);
		m_bIsChanged = false;
	}

	return bReturn;
}

bool TextToolWindow::SaveFile(void)
{
	/*----------------------------------*/
	/* Variable Declaration				*/
	/*----------------------------------*/
	wxFileDialog			clsSaveFileDialog(this, wxT("Save to file."), wxEmptyString, wxEmptyString,
										wxT("Text file (*.txt)|*.txt|All files (*.*)|*.*"), wxFD_SAVE);
	bool					bReturn;
	/*----------------------------------*/
	/* Process							*/
	/*----------------------------------*/
    if(wxID_OK == clsSaveFileDialog.ShowModal())
    {
		/* Save as text file. */
		bReturn = m_pclsInputTextCtrl->SaveFile(clsSaveFileDialog.GetPath());
		SetFilePath(clsSaveFileDialog.GetPath());
    }
    else
	{
		bReturn = false;
	}

	return bReturn;
}
